<template>
  <div>
    <message-form @refresh="fetchData"></message-form>

    <div :style="{height: `${height}px`}" ref="container" class="container message-container">
      <div
        v-for="item in data"
        :key="item.id"
        ref="wrap"
        :style="{opacity: isReady ? 1 : 0.1}"
        class="message-item"
      >
        <div :style="{background: (item.color || 'white')}" class="paper">
          <time class="time">{{ item.create_time }}</time>
          <img class="message-image" v-if="item.url" :src="item.url">
          <p>{{ item.message }}</p>
          <div class="address">{{ item.address }}</div>
          <span class="name">{{ item.name }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import request from '~/assets/request'

import MessageForm from '~/components/messageForm'

export default {
  name: 'message',
  head() {
    return {
      title: '卢忠宽的留言'
    }
  },
  data() {
    return {
      height: 0,
      isReady: false,
      itemWidth: 0
    }
  },
  async asyncData() {
    const { data } = await request({
      url: `/api/message`,
    }, { isCache: false })
    return { data: data.list }
  },
  methods: {
    color() {
      const colors = ['#ccf', '#cfc', '#fcc', '#ffc', '#cff', '#fcf']
      return colors[Math.floor(Math.random() * colors.length)]
    },
    setColor() {
      this.data.forEach(item => item.color = this.color())
      this.data = [...this.data]
    },
    allReady() {
      const { wrap } = this.$refs
      const len = wrap.length
      const promiseMap = []
      for (let i = 0; i < len; i++) {
        const el = wrap[i]
        promiseMap.push(isReady(el))
      }
      return Promise.all(promiseMap)
    },
    getColNum() {
      // 获取列数，设置容器宽度
      const { container, wrap } = this.$refs
      const conW = container.clientWidth
      const itemW = wrap[0].clientWidth
      const colNum = ~~(conW / itemW)
      container.style.width = `${(colNum * itemW) || itemW}px`
      this.itemWidth = itemW
      return colNum
    },
    setPos(hMap) {
      const { wrap } = this.$refs
      const len = wrap.length
      for (let i = 0; i < len; i++) {
        // 获取最小高度对应组下标
        const minHeight = Math.min(...hMap)
        let minIndex = hMap.findIndex((item) => item === minHeight)
        if (minIndex === -1) minIndex = 0

        // 设置item位置
        const el = wrap[i]
        hMap[minIndex] += el.clientHeight
        el.style.left = `${this.itemWidth * minIndex}px`
        el.style.top = `${minHeight}px`
      }

      // 设置最外层容器高度
      this.height = !hMap.length ? hMap : Math.max(...hMap)
    },
    initWaterFall() {
      this.$nextTick(async () => {
        // 没有数据直接返回
        if (!this.data.length) return
        // 再次获取宽度的时候，可以获取自适应宽度
        this.$refs.container.removeAttribute('style')
        // 等待图片加载
        await this.allReady()
        this.isReady = true
        // 设置容器宽度
        const colNum = this.getColNum() || 1
        // 获取默认各组高度
        const hMap = getDefaultHeightMap(colNum)
        this.setPos(hMap)
      })
    },
    async fetchData() {
      const { data } = await request({
        url: `/api/message`
      }, { isCache: false })
      this.data = []
      this.$nextTick(() => {
        this.data = data.content
        this.setColor()
        this.initWaterFall()
      })
    },
    resize() {
      debounce(() => {
        this.initWaterFall()
      })()
    }
  },
  mounted() {
    // 设置默认随机颜色
    this.setColor()
    // 初始化瀑布流
    this.initWaterFall()
    if (typeof window !== 'undefined') {
      window.addEventListener('resize', this.resize)
    }
  },
  beforeDestroy() {
    if (typeof window !== 'undefined') {
      window.removeEventListener('resize', this.resize)
    }
  },
  components: {
    MessageForm
  }
}

// 等待图片加载完成，获取高度（在resize的时候等待图片加载),只会判断每个waterFallItem组件中，只能放一张图片
function isReady(el) {
  return new Promise(resolve => {
    let img
    if (el.tagName === 'IMG') {
      img = el
    } else {
      img = el.querySelector('img')
    }
    if (!img) {
      resolve()
    } else if (img.complete) {
      resolve()
      return
    }
    img.onload = resolve
    img.onerror = resolve
  })
}

// 获取各组默认高度 [0, 0, 0 ...]
function getDefaultHeightMap(colNum = 1, arr = []) {
  if (arr.length < colNum) {
    arr.push(0)
    return getDefaultHeightMap(colNum, arr)
  }
  return arr
}

// 防抖函数
function debounce(fn, time = 300) {
  if (typeof fn !== 'function') {
    throw new Error('必须传入一个函数作为参数')
  }
  let timer
  return () => {
    timer && clearTimeout(timer)

    timer = setTimeout(() => {
      fn()
    }, time)
  }
}

</script>

<style lang="scss" scoped>
.message-container {
  line-height: 1.3;
  max-width: 1300px;
}

.paper {
  width: 320px;
  max-width: 100%;
  min-height: 160px;
  margin: 0 auto;
  box-sizing: border-box;
  padding: 20px 20px 36px;
  box-shadow: 2px 2px 20px #ccc;
}

.paper:hover {
  box-shadow: 2px 2px 40px #bbb;
}

.time {
  font-size: 14px;
  line-height: 24px;
}

p {
  font-size: 16px;
  line-height: 22px;
  margin: 20px 0;
  min-height: 20px;
  text-indent: 1em;
}

.address {
  font-size: 14px;
  color: #999;
  line-height: 14px;
}

.name {
  float: right;
  font-size: 14px;
}

.message-item {
  left: 0;
  top: 0;
  position: absolute;
  transition: left 0.3s, right 0.3s, opacity 0.3s;
  padding: 20px;
  box-sizing: border-box;
}

.message-image {
  width: 100%;
}

@media (max-width: 400px) {
  .message-item {
    max-width: 320px;
    position: relative;
    margin: 0 auto;
    left: 0 !important;
    top: 0 !important;
  }
}
</style>
